;author:杨淏天
.486
porta equ 3c0h
portb equ 3c4h
portc equ 3c8h
ctrl equ  3cch
code segment use16
assume cs:code
        org 1000h
        jmp start
savesong1 db  50 dup(00h) ;存储歌曲的变量
savesong2 db  50 dup(00h)
savesong3 db  50 dup(00h)
savesong4 db  50 dup(00h)
savesong5 db  50 dup(00h)      
song1  db 1,4,7,6,2,3,0ah,0eh,0ah,9,8,5,0ch,0ch,0dh,1,3,0dh,3,5,8,0dh,0
song2  db 6,8,0eh,5,0ah,0ch,4,0ah,0dh,6,3,1,5,2,0ch,7,0ah,0dh,2,5,0ah,1,0

key_result db 00h
key_result_son db 00h
disptab db 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,88H,83H,0C6H,0A1H,86H,8EH
DISPTABA DB 0A1H,0CEH,0FFH,8EH,92H,0C7H,92H
DISPTABB DB 0A3H,86H,0F9H,0A0H,0A3H,0A0H,0F9H 
kettab  db  0eeh,0edh,0ebh,0e7h,0deh,0ddh
        db  0dbh,0d7h,0beh,0bdh,0bbh,0b7h  ;字形表
        db  07eh,07dh,07bh,077h


MULUA EQU 00302479H             ;目录展示
MULUB EQU  00E18C8EH          ;鏄剧 ? - - -
F_ENDA EQU  0C80EH
F_ENDB EQU  0A186H
CHOOSEA EQU 0092C0C6H
CHOOSEB EQU 0086C089H
PAUSEA EQU 0086C18CH
PAUSEB EQU 00009288H



delay_time dw 0200h
delay_time_short dw  0fffh        ;delay函数的延时时间
do dw 0111111111111110b
re dw 0011111111111100b
mi dw 0001111111111000b
fa dw 0000111111110000b
sol dw 0000011111100000b
la dw  0000001111000000b
xi dw  0000000110000000b
do_high dw 0111111001111110b
re_high dw 0011111001111100b
mi_high dw 0001111001111000b
fa_high dw 0000111001110000b
sol_high dw 0000011001100000b
la_high dw 0000001001000000b
xi_high dw 0000000000000000b
delay_time_alter dd 0fff321h


;*******************
;主程序开始;
;*******************
start:  call init_8255
        CALL SMULU
        call test_key  ; 第一次测试键盘进大循环
        cmp key_result,1
        jz  func1 ;按下一：自由弹 
        cmp key_result,2
        jz  func2 ;按下二：弹曲库 
        cmp key_result,3
        jz   func3 ;按下三：存入音乐 
        jmp  start  
func1: ; 自由弹奏模式，输入随动
        call test_key
        call funcview
func1_loop:  call key_perform
             call noteview
             call test_key   ;检测按键，按下F返回主菜单
             cmp  key_result,0fh
             jz   start
             jmp  func1_loop
func2:          
            call SCHOOSE
		call test_key
		call  change_di
		call SPEED_VIEW
		call test_key
		call change_speed
                call key_perform_auto  ;自动演奏内部集成了暂停，返回上级功能
                jmp start
 
func3:          call funcview
                call savesong
                jmp start
;***********************************************8
;主程序结束
;*************************************************



;/***************
;涓荤▼搴忚嚦姝ょ粨鏉?
;涓 ??潰涓哄皝瑁呭ソ鐨 ?嚱鏁?
;*/
;涓 ??潰涓哄搴斿姛鑳界殑鍑芥 ?   
;@@func SMULU
;@@param  MULUA MULUB
;@@brief 鏄剧 ?1- 2- 3-
;@@return none
SMULU   PROC NEAR
	pushad
        MOV DX, 20CH            ;鍒濆鍖?255
        MOV EAX,80808080H
        OUT DX, EAX
        MOV DX, 200H            ;A鍙ｆ樉绀? 2 3
        MOV EAX,MULUA
        OUT DX, EAX
        MOV DX, 204H            ;B鍙ｆ樉绀? - -
        MOV EAX,MULUB
        OUT DX, EAX
        MOV DX, 208H
        MOV EAX,0F050505H
        OUT DX, EAX
        popad
        RET
SMULU   ENDP


;@@func delay
;@@param delay_time 寰幆娆℃暟
;@@brief 寤舵椂鍑芥暟
;@@return none
delay   proc    near
        push    cx
        mov     cx,delay_time
dlp:    loop    dlp
	pop cx
        ret
delay  endp

delay_short   proc    near
        push    ecx
        mov     ecx,0ffffffffh
dlp_short:    loop    dlp_short
	pop ecx
        ret
delay_short  endp

delay_long   proc    near
        push    ecx
        mov     ecx,4fffffh
dlp_long:    loop   dlp_long
	pop ecx
        ret
delay_long  endp

delay_alter   proc    near
        push    ecx
        mov     ecx,delay_time_alter
dlp_long_alter:    
	;call test_key_none
	;cmp key_result_son,0fh
	;jz  quit1  
	loopd   dlp_long_alter
quit1	:pop ecx
        ret
delay_alter  endp

;@@func test_key
;@@param none
;@@brief 测试键盘输入    PC4-PC7-->Q0-Q3  C0-C3-->P0-P3
;@@return key_result->按下的按键值（0-f ） 没有按键按下时等待
test_key proc    near
        pushad
t2:      mov al,00h
        mov dx,portc
        out dx,al
        mov dx,portc
loop1:  in  al,dx
        and al,0fh
        cmp al,0fh
        je  loop1
        mov bh,al          
        call    delay_long
        mov al,0efh
        mov bl,al
loop2:   mov dx,portc
        out dx,al
        mov dx,portc
        in  al,dx
        and al,0fh
        cmp al,0fh
        jne loop3
        rol bl,1
        mov al,bl   
        jmp loop2
loop3:  ;mov cl,4
        ;sal bl,cl
        and bl,0f0h
        or  bl,bh
        call    delay
        lea si,kettab
       mov  bh,0
loop4:  mov al,[si]
        cmp al,bl
        je  loop5
        inc bh
        inc si
        jmp loop4
        
loop5:   mov key_result,bh
 ;下面检测按键是否抬起
        mov dx,portc
        mov al,00h
        out dx,al
        in  al,dx
        and al,0fh
        cmp al,0fh
        jne loop5
        popad
         ret

test_key endp

;@@func test_key_none
;@@param none
;@@brief 测试键盘输入    PC4-PC7-->Q0-Q3  C0-C3-->P0-P3
;@@return key_result_son->按下的按键值（0-f） 没有按键按下时返回0
test_key_none proc    near
        pushad
t2_none:      mov al,00h
        mov dx,portc
        out dx,al
        mov dx,portc
loop1_none:  in  al,dx
        and al,0fh
        cmp al,0fh
        je  nokey
        mov bh,al          
        call    delay_long
        mov al,0efh
        mov bl,al
loop2_none:   mov dx,portc
        out dx,al
        mov dx,portc
        in  al,dx
        and al,0fh
        cmp al,0fh
        jne loop3_none
        rol bl,1
        mov al,bl   
        jmp loop2_none
loop3_none:  ;mov cl,4
        ;sal bl,cl
        and bl,0f0h
        or  bl,bh
        call    delay
        lea si,kettab
       mov  bh,0
loop4_none:  mov al,[si]
        cmp al,bl
        je  loop5_none
        inc bh
        inc si
        jmp loop4_none
        
loop5_none:   mov key_result_son,bh
 ;下面检测按键否抬起
        mov dx,portc
        mov al,00h
        out dx,al
        in  al,dx
        and al,0fh
        cmp al,0fh
        jne loop5
        popad
         ret

nokey: mov key_result_son,0
         popad
         ret
test_key_none endp

;@@func key_perform_auto
;@@param di->保存的歌的首地址,以00h结束
;@@brief 根据按下的key来亮 形成演示   
;@@return none 
key_perform_auto proc    near
        pushad
        mov dx,208h
        mov eax,0f0f0f0fh
        out dx,eax
        ;call funcview
        mov ax,0
        lea si,do
loopinside:
	lea si,do
	
	  mov  ax,0
        mov al,[di]
        MOV KEY_RESULT,AL
       CALL NOTEVIEW
        dec al
        add si,ax
        add si,ax ;经过上述操作后，si 就是对应按键的灯
        mov ax,[si]
        mov dx,portb
        out dx,al
        mov al,ah
        mov dx, porta
        out dx,al ;送完 ，调延时
        call delay_alter
        call test_key_none;检测是否有按键按下,按下F暂停,E退出
         cmp key_result_son,0dh
         jz start
        cmp key_result_son,0fh
        jnz continue_loop
        call stop_show
continue_loop:      
        CMP key_result_son ,0eh
        JZ star
        inc di
        cmp [di],00h
        jz star
        jmp loopinside        
star:        popad
        ret
key_perform_auto endp

;@@func key_perform
;@@param key_result
;@@brief 根据按下的key来亮 形成演示   
;@@return none 
key_perform proc    near
        pushad
        mov ax,0
        lea si,do
        mov al,key_result
        dec al
        add si,ax
        add si,ax ;经过上述操作后，si ?就是对应按键的灯
        mov ax,[si]
        mov dx,portb
        out dx,al
        mov al,ah
        mov dx, porta
        out dx,al ;送完 ?，调延时
        call delay
        popad
        ret
key_perform endp

;@@func init_8255
;@@param none
;@@brief 初始化8255  
;@@return none 
init_8255 proc    near
        pushad
        mov dx,ctrl
        mov al,10000001b ; ?8255
        out dx,al
        popad
        ret
init_8255 endp
;@@func change_di
;@@param none
;@@brief 改变si
;@@return none 
change_di proc    near
	
	cmp key_result ,01h
	jz  one
	cmp key_result ,02h
	jz two
	cmp  key_result ,03h
	jz three
	cmp  key_result ,04h
	jz four
		cmp  key_result ,05h
	jz five
		cmp  key_result ,06h
	jz six
		cmp  key_result ,07h
	jz siven

one :    lea di,song1

	    ret
two:
          lea di,song2

          ret
 three:   lea di  ,savesong1

 		ret
 four:lea di  ,savesong2

 		ret
 five:lea di  ,savesong3

 		ret
 six:lea di  ,savesong4

 		ret
 siven:lea di  ,savesong5
  		ret
 		popad
        ret
change_di endp

;@@func change_speed
;@@param none
;@@brief 改变si
;@@return none 
change_speed proc    near
	pushad
	cmp key_result ,01h
	jz  one_speed
	cmp key_result ,02h
	jz two_speed
	cmp  key_result ,03h
	jz three_speed

one_speed :    mov delay_time_alter,003ffffh
popad
	    ret
two_speed:     mov delay_time_alter,001ffffh
popad
          ret
 three_speed:   mov delay_time_alter,08fffh
 popad
 		ret
        ret
change_speed endp
;@@func funcview
;@@param none
;@@brief 鏍 ? 嵁閿洏杈撳叆杩涘叆鍔熻兘
;@@return none
funcview  proc
pushad
    cmp key_result,1
    jz s1
    cmp key_result,2
    jz s2
    cmp key_result,3
    jz s3
    jmp fv_end
s1: 
    mov dx,200h
    mov ax,0c68eh
    out dx,ax
    mov dx,204h
    mov ax,0f9c1h
    out dx,ax
    jmp snext
s2:
    mov dx,200h
    mov ax,0c68eh
    out dx,ax
    mov dx,204h
    mov ax,0a4c1h
    out dx,ax
    jmp snext
s3:
    mov dx,200h
    mov ax,0c68eh
    out dx,ax
    mov dx,204h
    mov ax,0b0c1h
    out dx,ax
    jmp snext
snext:
    ;FUC_yellow
    mov dx,208h
    mov EAX,0F0F0000H
    out dx,EAX
fv_end:
popad
    ret
funcview endp

;@@func noteview        
;@@param diptab
;@@brief 鏄剧ず闊崇,浠ュ緟鏄剧ず鍊煎湪bh涓轰 ?
;@@return none
noteview proc
   PUSHAD
    cmp key_result,7 ;鍒ゆ柇 ? 樹綆闊?
    ja n2
n1: ;浣庨煶鏄剧ず缁胯 ?
    mov dx,20bh
    mov al,0Ah 
    out dx,al
    mov al,key_result
    jmp n3
n2: ;楂橀煶鏄剧ず绾㈣ ?
    mov dx,20bh
    mov al,05h 
    out dx,al
    mov al,key_result
    sub al,7
    jmp n3
n3: ;鏄剧ず鏁板瓧
    SUB AL,1
    MOV CL,AL
    lea bx,disptabA
    xlat
    mov dx,203h
    out dx,al
    MOV AL,CL
    LEA BX,DISPTABB
    XLAT
    MOV DX,207H
    OUT DX,AL
    POPAD
    ret
noteview endp

;@@func stop_show
;@@param none
;@@brief 在暂停的时候显示停止符号并且检测键盘,按下f退出
;@@return none
stop_show proc near
      pushad
 stop_loop:     call SPAUSE;修改为STOP函数
      call test_key_none
      cmp key_result_son,0fh
      jnz stop_loop
      mov dx,208h
      mov eax,0f0f0f0fh
      out dx,eax
      popad
      ret
stop_show endp

;@@func savesong
;@@param none
;@@brief 保存键盘输入的歌曲,没有键输入时等待，按0等待,按F退出保存， C4-C7-->Q0-Q3  C0-C3-->P0-P3
;@@return savesong1->返回保存的歌曲
;savesong proc near
 ;     pushad
   ;   mov dx,porta
  ;    mov al,0ffh
  ;    out dx,al
   ;   mov dx,portb
   ;   out dx,al
   ;   call delay_long
   ;   lea si,savesong1
;wait1:mov key_result,0
     ; call test_key
      ;call key_perform
      ;call noteview
      ;call delay
      ;mov dl,key_result
      ;cmp dl,0fh
      ;je exit
      ;cmp dl,00h
      ;je wait1
      ;mov al,key_result
      ;mov [si],al
      ;inc si
;     ;mov dx,porta
;      mov al,0ffh
;      out dx,al
 ;     mov dx,portb
 ;     out dx,al
      ;call delay_long
      ;jmp wait1
;exit: popad 
 ;     ret
;savesong endp
;@@func SPAUSE
;@@param  PAUSEA PAUSEB
;@@brief 显示PAUSE
;@@return none
SPAUSE   PROC NEAR
	PUSHAD
        MOV DX, 20CH            
        MOV EAX,80808080H
        OUT DX, EAX
        MOV DX, 200H            
        MOV EAX, PAUSEA
        OUT DX, EAX
        MOV DX, 204H            
        MOV EAX, PAUSEB
        OUT DX, EAX
        MOV DX, 208H
        MOV EAX,0F0D0505H
        OUT DX, EAX
         POPAD
        RET

SPAUSE   ENDP

;@@func SCHOOSE
;@@param  CHOOSEA CHOOSEB
;@@brief 显示CHOOSE
;@@return none
SCHOOSE   PROC NEARE
        PUSHAD 
        MOV DX, 20CH            
        MOV EAX,80808080H
        OUT DX, EAX
        MOV DX, 200H            
        MOV EAX, CHOOSEA
        OUT DX, EAX
        MOV DX, 204H 
        MOV EAX, CHOOSEB           
        OUT DX, EAX
        MOV DX, 208H
        MOV EAX,0F050505H
        OUT DX, EAX
        POPAD
        RET
SCHOOSE   ENDP

;@@func SPAUSE
;@@param  PAUSEA PAUSEB
;@@brief 显示PAUSE
;@@return none
SF_END   PROC NEAR
	PUSHAD
        MOV DX, 20CH            
        MOV EAX,80808080H
        OUT DX, EAX
        MOV DX, 200H            
        MOV AX, F_ENDA
        OUT DX, AX
        MOV DX, 204H            
        MOV AX, F_ENDB
        OUT DX, AX
        MOV DX, 208H
        MOV EAX,0F0f0505H
        OUT DX, EAX
        POPAD
        RET
SF_END   ENDP
speed_view proc 
pushad
mov dx,208h
mov eax,0
out dx,eax
mov dx,200h
mov eax,0ffa18692h
out dx,eax
mov dx,204h
mov eax,0ffff868ch
out dx,eax
popad
RET
endp speed_view
;@@func savesong
;@@param none
;@@brief 保存键盘输入的歌曲,没有键输入时等待，按0等待,按F退出保存， C4-C7-->Q0-Q3  C0-C3-->P0-P3
;@@return savesong1->返回保存的歌曲
savesong proc near
      pushad
      mov dx,porta
      mov al,0ffh
      out dx,al
      mov dx,portb
      out dx,al
insidelop1: 
      call schoose    
      lea si,savesong1
      call delay_long
      call test_key
      call SONGview
      cmp key_result,1
      je ee1
      cmp key_result,2
      je ee2
      cmp key_result,3
      je ee3
      cmp key_result,4
      je ee4
      cmp key_result,5
      je ee5
      cmp key_result,0fh
      jmp exit
      jmp insidelop1
ee1:  mov cl,0
      jmp wait1
ee2:  mov cl,0
      add si,50
      jmp wait1
ee3:  mov cl,0
      add si,100
      jmp wait1
ee4:  mov cl,0
      add si,150
      jmp wait1
ee5:  mov cl,0
      add si,200
      jmp wait1
wait1:
      mov key_result,0
      call delay_long
      call test_key
      call key_perform
      call noteview
      call delay
      mov dl,key_result
      cmp dl,0fh
      je exit
      cmp dl,00h
      je qiehuan
      mov al,key_result
      mov [si],al
      inc si
      inc cl
      call delay_long
      jmp wait1
qiehuan:
      xor bx,bx
      mov bl,49
      sub bl,cl
      add si,bx
      mov [si],00h
      jmp insidelop1
exit: xor bx,bx
      mov bl,49
      sub bl,cl
      add si,bx
      mov [si],00h
      popad 
      ret
savesong endp
SONGview  proc
    PUSHAD
    cmp key_result,1
    jz sS1
    cmp key_result,2
    jz sS2
    cmp key_result,3
    jz sS3
    CMP KEY_RESULT,4
    JZ SS4
    CMP KEY_RESULT,5
    JZ SS5
    jmp S_end
sS1: 
    mov dx,200h
    mov Eax,0FFF9C892h
    out dx,Eax
    mov dx,204h
    mov Eax,0FFFF90C0h
    out dx,Eax
    jmp Ssnext
sS2: 
    mov dx,200h
    mov Eax,0FFA4C892h
    out dx,Eax
    mov dx,204h
    mov Eax,0FFFF90C0h
    out dx,Eax
    jmp Ssnext
sS3: 
    mov dx,200h
    mov Eax,0FFB0C892h
    out dx,Eax
    mov dx,204h
    mov Eax,0FFFF90C0h
    out dx,Eax
    jmp Ssnext
sS4: 
    mov dx,200h
    mov Eax,0FF99C892h
    out dx,Eax
    mov dx,204h
    mov Eax,0FFFF90C0h
    out dx,Eax
    jmp Ssnext
sS5: 
    mov dx,200h
    mov Eax,0FF92C892h
    out dx,Eax
    mov dx,204h
    mov Eax,0FFFF90C0h
    out dx,Eax

sSnext:
    ;FUC_yellow
    mov dx,208h
    mov EAX,0H
    out dx,EAX
S_end:
    POPAD
    ret
SONGview endp
code    ends
end start
